package com.xiyu.service.service.material;

import com.xiyu.service.model.material.order.MaterialTransferDetail;
import com.xiyu.service.repository.material.stock.MaterialStockDetailRepository;
import com.xiyu.service.vo.material.transfer.TransferSingleGetDetailOutput;
import com.xiyu.service.enums.material.order.MaterialTransferStatusEnum;
import com.xiyu.service.model.material.order.*;
import com.xiyu.service.service.infra.data.DictNoService;
import com.xiyu.service.vo.material.transfer.TransferUpdateStatusInput;
import com.xiyu.service.vo.material.transfer.TransferSingleGetOutput;
import com.xiyu.service.repository.material.order.MaterialTransferDetailRepository;
import com.xiyu.service.vo.material.transfer.TransferUpdateInput;
import com.xiyu.service.vo.material.transfer.TransferCreateInput;
import com.xiyu.service.repository.material.order.MaterialTransferRepository;
import com.xiyu.service.vo.material.transfer.TransferPageQueryOutput;
import com.xiyu.service.vo.material.transfer.TransferPageQueryInput;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.babyfish.jimmer.Page;

import java.util.*;

import org.springframework.transaction.annotation.Transactional;

import java.util.stream.Collectors;

import com.xiyu.service.framework.web.web.core.pojo.PageResult;
import com.xiyu.service.convert.material.TransferConvert;
import com.xiyu.service.util.entity.EntityUtils;
import org.babyfish.jimmer.DraftObjects;

import static com.xiyu.service.framework.exception.util.ServiceExceptionUtil.exception;
import static com.xiyu.service.errorCode.material.TransferErrorCode.*;

/**
 * 调拨单管理 Service 实现类
 */
@Service
@Validated
public class TransferServiceImpl implements TransferService {

    @Resource
    private MaterialTransferDetailRepository materialTransferDetailRepository;

    @Resource
    private MaterialTransferRepository materialTransferRepository;

    @Resource
    private DictNoService dictNoService;

    @Resource
    private MaterialStockDetailRepository materialStockDetailRepository;


    @Override
    public PageResult<TransferPageQueryOutput> pageQuery(TransferPageQueryInput inputVO) {
        Page<MaterialTransfer> pageMaterialTransfer = materialTransferRepository.pageQuery(inputVO);
        List<TransferPageQueryOutput> listMaterialTransfer = TransferConvert.INSTANCE.pageQueryOutputConvert(pageMaterialTransfer.getRows());
        return new PageResult<>(listMaterialTransfer, pageMaterialTransfer.getTotalRowCount());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(TransferCreateInput inputVO) {
        MaterialTransfer newMaterialTransfer = TransferConvert.INSTANCE.createInputConvert(inputVO);
        List<MaterialTransferDetail> details = newMaterialTransfer.details();
        if(details.isEmpty()){
            throw exception(MATERIAL_TRANSFER_DETAIL_NOT_EMPTY);
        }
        newMaterialTransfer = MaterialTransferDraft.$.produce(newMaterialTransfer, draft -> {
            draft.setTransferNo(dictNoService.produceNo("transfer"))
                    .setStatus(MaterialTransferStatusEnum.PENDING_REVIEW.getValue());
            DraftObjects.unload(draft, MaterialTransferProps.DETAILS);
        });
        newMaterialTransfer = materialTransferRepository.insert(newMaterialTransfer);
        MaterialTransfer finalNewMaterialTransfer = newMaterialTransfer;
        details = details.stream().map(detail-> MaterialTransferDetailDraft.$.produce(detail, draft -> {
            draft.setTransferId(finalNewMaterialTransfer.id());
        })).collect(Collectors.toList());
        materialTransferDetailRepository.saveAll(details);
        return newMaterialTransfer.id();

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(TransferUpdateInput inputVO) {
        Optional<MaterialTransfer> optionalOldMaterialTransfer = materialTransferRepository.findById(inputVO.getId());
        if(!optionalOldMaterialTransfer.isPresent()){
            throw exception(MATERIAL_TRANSFER_NOT_EXIST);
        }
        for(TransferUpdateInput.detail detail : inputVO.getDetails()){
            if(Objects.equals(detail.getOperateType(), "delete")){
                Optional<MaterialTransferDetail> optionalDeleteMaterialTransferDetail = materialTransferDetailRepository.findById(detail.getId());
                if(!optionalDeleteMaterialTransferDetail.isPresent()){
                    throw exception(MATERIAL_TRANSFER_DETAIL_NOT_EXIST);
                }
                materialTransferDetailRepository.deleteById(detail.getId());
            }else if(Objects.equals(detail.getOperateType(), "new")){
                MaterialTransferDetail newMaterialTransferDetail = TransferConvert.INSTANCE.updateInputConvert(detail);
                materialTransferDetailRepository.insert(newMaterialTransferDetail);
            }else{
                Optional<MaterialTransferDetail> optionalOldMaterialTransferDetail = materialTransferDetailRepository.findById(detail.getId());
                if(!optionalOldMaterialTransferDetail.isPresent()) {
                    throw exception(MATERIAL_TRANSFER_DETAIL_NOT_EXIST);
                }
                MaterialTransferDetail updateMaterialTransferDetail = TransferConvert.INSTANCE.updateInputConvert(detail);
                if (!EntityUtils.isEquals(optionalOldMaterialTransferDetail.get(), updateMaterialTransferDetail))
                    materialTransferDetailRepository.update(updateMaterialTransferDetail);
            }
        }
        if(materialTransferDetailRepository.findByTransferId(inputVO.getId()).isEmpty()){
            throw exception(MATERIAL_TRANSFER_DETAIL_NOT_EMPTY);
        }
        MaterialTransfer updateMaterialTransfer = TransferConvert.INSTANCE.updateInputConvert(inputVO);
        updateMaterialTransfer = MaterialTransferDraft.$.produce(updateMaterialTransfer, draft -> {
            DraftObjects.unload(draft, MaterialTransferProps.DETAILS);
        });
        if (!EntityUtils.isEquals(optionalOldMaterialTransfer.get(), updateMaterialTransfer))
            materialTransferRepository.update(updateMaterialTransfer);
        return true;
    }

    @Override
    public TransferSingleGetOutput singleGet(Long id) {
        Optional<MaterialTransfer> optionMaterialTransfer = materialTransferRepository.findDetailById(id);
        if(!optionMaterialTransfer.isPresent()){
            throw exception(MATERIAL_TRANSFER_NOT_EXIST);
        }

        return TransferConvert.INSTANCE.singleGetOutputConvert(optionMaterialTransfer.get());

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateStatus(TransferUpdateStatusInput inputVO) {
        Optional<MaterialTransfer> optionMaterialTransfer = materialTransferRepository.findById(inputVO.getId());
        if(!optionMaterialTransfer.isPresent()){
            throw exception(MATERIAL_TRANSFER_NOT_EXIST);
        }
        MaterialTransfer materialTransfer = optionMaterialTransfer.get();
        switch (inputVO.getAction()){
            // 审核调拨单
            case "review":
                if(!materialTransfer.status().equals(MaterialTransferStatusEnum.PENDING_REVIEW.getValue())){
                    throw exception(MATERIAL_TRANSFER_NOT_PENDING_REVIEW);
                }
                materialTransfer = MaterialTransferDraft.$.produce(materialTransfer, draft -> {
                    draft.setStatus(MaterialTransferStatusEnum.PENDING_OUT.getValue());
                });
                break;
            // 取消调拨单
            case "cancel":
                if(!materialTransfer.status().equals(MaterialTransferStatusEnum.PENDING_REVIEW.getValue())){
                    throw exception(MATERIAL_TRANSFER_NOT_PENDING_REVIEW);
                }
                materialTransfer = MaterialTransferDraft.$.produce(materialTransfer, draft -> {
                    draft.setStatus(MaterialTransferStatusEnum.CANCEL.getValue());
                });
                break;
            // 反审核调拨单
            case "revertReview":
                if(!materialTransfer.status().equals(MaterialTransferStatusEnum.PENDING_OUT.getValue())){
                    throw exception(MATERIAL_TRANSFER_NOT_PENDING_IN);
                }
                materialTransfer = MaterialTransferDraft.$.produce(materialTransfer, draft -> {
                    draft.setStatus(MaterialTransferStatusEnum.PENDING_REVIEW.getValue());
                });
                break;
            // 停止出库
            case "stopOut":
                if(!materialTransfer.status().equals(MaterialTransferStatusEnum.PARTIAL_OUT.getValue())){
                    throw exception(MATERIAL_TRANSFER_NOT_PARTIAL_OUT);
                }
                materialTransfer = MaterialTransferDraft.$.produce(materialTransfer, draft -> {
                    draft.setStatus(MaterialTransferStatusEnum.PARTIAL_OUT.getValue());
                });
                break;
            // 停止入库
            case "stopIn":
                if(!materialTransfer.status().equals(MaterialTransferStatusEnum.PARTIAL_IN.getValue())){
                    throw exception(MATERIAL_TRANSFER_NOT_PARTIAL_IN);
                }
                materialTransfer = MaterialTransferDraft.$.produce(materialTransfer, draft -> {
                    draft.setStatus(MaterialTransferStatusEnum.COMPLETED.getValue());
                });
                break;
        }
        materialTransferRepository.update(materialTransfer);
        return true;
    }

    @Override
    public List<TransferSingleGetDetailOutput> singleGetDetail(Long transferId) {
        List<MaterialTransferDetail> optionMaterialTransferDetail = materialTransferDetailRepository.findDetailByTransferId(transferId);
        return TransferConvert.INSTANCE.singleGetDetailOutputConvert(optionMaterialTransferDetail);
    }

}
